home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / engrave.c < prev    next >
C/C++ Source or Header  |  1992-10-22  |  24KB  |  959 lines

  1. /*    SCCS Id: @(#)engrave.c    3.1    92/02/25    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6. #include "lev.h"
  7. #include <ctype.h>
  8.  
  9. STATIC_VAR struct engr NEARDATA *head_engr;
  10.  
  11. STATIC_DCL void FDECL(del_engr, (struct engr *));
  12.  
  13. #ifdef OVLB
  14. /* random engravings */
  15. const char *random_mesg[] = {
  16.     "Elbereth", "ad ae?ar um",
  17.     "?la? ?as he??",
  18.     /* take-offs and other famous engravings */
  19.     "Owlbreath", "?ala??iel",
  20.     "?ilroy wa? h?re",
  21.     "A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */
  22.     "Y?u won t get i? up ?he ste?s", /* Adventure */
  23.     "Lasc?ate o?ni sp?ranz? o vo? c?'en?rate", /* Inferno */
  24.     "Well Come", /* Prisoner */
  25.     "W? ap?l???ze for t?e inc?nve??e?ce", /* So Long... */
  26.     "S?e you n?xt Wed?esd?y", /* Thriller */
  27.     "Fo? a ?ood time c?ll 8?7-53?9",
  28. };
  29.  
  30. const char *
  31. random_engraving()
  32. {
  33.     char *rumor, *s;
  34.  
  35. /* a random engraving may come from the "rumors" file, or from the
  36.    list above */
  37.     rumor = getrumor(0);
  38.     if (rn2(4) && *rumor) {
  39.         for (s = rumor; *s; s++)
  40.             if (!rn2(7) && *s != ' ') *s = '?';
  41.         if (s[-1] == '.') s[-1] = 0;
  42.         return (const char *)rumor;
  43.     }
  44.     else
  45.         return random_mesg[rn2(SIZE(random_mesg))];
  46. }
  47. #endif /* OVLB */
  48. #ifdef OVL0
  49.  
  50. struct engr *
  51. engr_at(x,y) register xchar x,y; {
  52. register struct engr *ep = head_engr;
  53.     while(ep) {
  54.         if(x == ep->engr_x && y == ep->engr_y)
  55.             return(ep);
  56.         ep = ep->nxt_engr;
  57.     }
  58.     return((struct engr *) 0);
  59. }
  60.  
  61. #ifdef ELBERETH
  62. int
  63. sengr_at(s,x,y)
  64.     register const char *s;
  65.     register xchar x,y;
  66. {
  67.     register struct engr *ep = engr_at(x,y);
  68.     register char *t;
  69.     register int n;
  70.  
  71.     if(ep && ep->engr_time <= moves) {
  72.         t = ep->engr_txt;
  73. /*
  74.         if(!strcmp(s,t)) return(1);
  75. */
  76.         n = strlen(s);
  77.         while(*t) {
  78.             if(!strncmp(s,t,n)) return(1);
  79.             t++;
  80.         }
  81.     }
  82.     return(0);
  83. }
  84. #endif
  85.  
  86. #endif /* OVL0 */
  87. #ifdef OVL2
  88.  
  89. void
  90. u_wipe_engr(cnt)
  91. register int cnt;
  92. {
  93.     if(!u.uswallow && !Levitation)
  94.         wipe_engr_at(u.ux, u.uy, cnt);
  95. }
  96.  
  97. #endif /* OVL2 */
  98. #ifdef OVL1
  99.  
  100. void
  101. wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
  102. register struct engr *ep = engr_at(x,y);
  103. register int lth,pos;
  104. char ch;
  105.     if(ep){
  106.         if(ep->engr_type != BURN) {
  107.         if(ep->engr_type != DUST && ep->engr_type != BLOOD) {
  108.             cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
  109.         }
  110.         lth = strlen(ep->engr_txt);
  111.         if(lth && cnt > 0 ) {
  112.             while(cnt--) {
  113.                 pos = rn2(lth);
  114.                 if((ch = ep->engr_txt[pos]) == ' ')
  115.                     continue;
  116.                 ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
  117.             }
  118.         }
  119.         while(lth && ep->engr_txt[lth-1] == ' ')
  120.             ep->engr_txt[--lth] = 0;
  121.         while(ep->engr_txt[0] == ' ')
  122.             ep->engr_txt++;
  123.         if(!ep->engr_txt[0]) del_engr(ep);
  124.         }
  125.     }
  126. }
  127.  
  128. #endif /* OVL1 */
  129. #ifdef OVL2
  130.  
  131. void
  132. read_engr_at(x,y)
  133. register int x,y;
  134. {
  135.     register struct engr *ep = engr_at(x,y);
  136.     register int    sensed = 0;
  137.  
  138.     if(ep && ep->engr_txt[0]) {
  139.         switch(ep->engr_type) {
  140.         case DUST:
  141.         if(!Blind) {
  142.             sensed = 1;
  143.             pline("Something is written here in the dust.");
  144.         }
  145.         break;
  146.         case ENGRAVE:
  147.         if(!Blind || !Levitation) {
  148.             sensed = 1;
  149.             pline("Something is engraved here on the floor.");
  150.         }
  151.         break;
  152.         case BURN:
  153.         if(!Blind || !Levitation) {
  154.             sensed = 1;
  155.             pline("Some text has been burned into the floor here.");
  156.         }
  157.         break;
  158.         case MARK:
  159.         if(!Blind) {
  160.             sensed = 1;
  161.             pline("There's some graffiti on the floor here.");
  162.         }
  163.         break;
  164.         case BLOOD:
  165.         /* "It's a message!  Scrawled in blood!"
  166.          * "What's it say?"
  167.          * "It says... `See you next Wednesday.'" -- Thriller
  168.          */
  169.         if(!Blind) {
  170.             sensed = 1;
  171.             You("see a message scrawled in blood here.");
  172.         }
  173.         break;
  174.         default:
  175.         impossible("Something is written in a very strange way.");
  176.         sensed = 1;
  177.         }
  178.         if (sensed) {
  179.         You("%s: \"%s\".",
  180.               (Blind) ? "feel the words" : "read",  ep->engr_txt);
  181.         if(flags.run > 1) nomul(0);
  182.         }
  183.     }
  184. }
  185.  
  186. #endif /* OVL2 */
  187. #ifdef OVLB
  188.  
  189. void
  190. make_engr_at(x,y,s,e_time,e_type)
  191. register int x,y;
  192. register const char *s;
  193. register long e_time;
  194. register xchar e_type;
  195. {
  196.     register struct engr *ep;
  197.  
  198.     if(ep = engr_at(x,y))
  199.         del_engr(ep);
  200.     ep = newengr(strlen(s) + 1);
  201.     ep->nxt_engr = head_engr;
  202.     head_engr = ep;
  203.     ep->engr_x = x;
  204.     ep->engr_y = y;
  205.     ep->engr_txt = (char *)(ep + 1);
  206.     Strcpy(ep->engr_txt, s);
  207.     if(strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
  208.     ep->engr_time = e_time;
  209.     ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE);
  210.     ep->engr_lth = strlen(s) + 1;
  211. }
  212.  
  213. /*
  214.  *    freehand - returns true if player has a free hand
  215.  */
  216. int
  217. freehand()
  218. {
  219.     return(!uwep || !welded(uwep) ||
  220.        (!bimanual(uwep) && (!uarms || !uarms->cursed)));
  221. /*    if ((uwep && bimanual(uwep)) ||
  222.         (uwep && uarms))
  223.         return(0);
  224.     else
  225.         return(1);*/
  226. }
  227.  
  228. static const char NEARDATA styluses[] =
  229.     { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
  230.       GEM_CLASS, RING_CLASS, 0 };
  231.  
  232. /* Mohs' Hardness Scale:
  233.  *  1 - Talc         6 - Orthoclase
  234.  *  2 - Gypsum         7 - Quartz
  235.  *  3 - Calcite         8 - Topaz
  236.  *  4 - Fluorite     9 - Corundum
  237.  *  5 - Apatite        10 - Diamond
  238.  *
  239.  * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
  240.  * probably be able to scratch the rock.
  241.  * Devaluation of less hard gems is not easily possible because obj struct
  242.  * does not contain individual oc_cost currently. 7/91
  243.  *
  244.  * dilithium  - ??            * jade        -  5-6    (nephrite)
  245.  * diamond    - 10            * turquoise -  5-6
  246.  * ruby          -  9    (corundum)    * opal        -  5-6
  247.  * sapphire   -  9    (corundum)    * iron        -  4-5
  248.  * topaz      -  8            * fluorite  -  4
  249.  * emerald    -  7.5-8    (beryl)        * brass     -  3-4
  250.  * aquamarine -  7.5-8    (beryl)        * gold        -  2.5-3
  251.  * garnet     -  7.25    (var. 6.5-8)    * silver    -  2.5-3
  252.  * agate      -  7    (quartz)    * copper    -  2.5-3
  253.  * amethyst   -  7    (quartz)    * amber     -  2-2.5
  254.  * jasper     -  7    (quartz)    *    
  255.  * onyx          -  7     (quartz)    * steel     -  5-8.5    (usu. weapon)
  256.  * moonstone  -  6    (orthoclase)    *
  257.  */
  258.  
  259. static const short NEARDATA hard_gems[] =
  260.     { DIAMOND, RUBY, SAPPHIRE, TOPAZ, EMERALD, AQUAMARINE, GARNET, 0 };
  261.  
  262. static const char NEARDATA *hard_ring_names[] =
  263.     {"diamond", "ruby", "sapphire", "emerald", "topaz", ""};
  264.  
  265. /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
  266. int
  267. doengrave()
  268. {
  269.     boolean dengr = FALSE;    /* TRUE if we wipe out the current engraving */
  270.     boolean doblind = FALSE;/* TRUE if engraving blinds the player */
  271.     boolean doknown = FALSE;/* TRUE if we identify the stylus */
  272.     boolean eow = FALSE;    /* TRUE if we are overwriting oep */
  273.     boolean jello = FALSE;    /* TRUE if we are engraving in slime */
  274.     boolean ptext = TRUE;    /* TRUE if we must prompt for engrave text */
  275.     boolean teleengr =FALSE;/* TRUE if we move the old engraving */
  276.     boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
  277.     xchar type = DUST;    /* Type of engraving made */
  278.     char buf[BUFSZ];    /* Buffer for final/poly engraving text */
  279.     char ebuf[BUFSZ];    /* Buffer for initial engraving text */
  280.     char qbuf[QBUFSZ];    /* Buffer for query text */
  281.     const char *everb;    /* Present tense of engraving type */
  282.     const char *eloc;    /* Where the engraving is (ie dust/floor/...) */
  283.     const char *post_engr_text; /* Text displayed after engraving prompt */
  284.     register char *sp;    /* Place holder for space count of engr text */
  285.     register int len;    /* # of nonspace chars of new engraving text */
  286.     register int maxelen;    /* Max allowable length of new engraving text */
  287.     register int spct;    /* # of spaces in new engraving text */
  288.     register struct engr *oep = engr_at(u.ux,u.uy);
  289.                 /* The current engraving */
  290.     register struct obj *otmp; /* Object selected with which to engrave */
  291.  
  292.  
  293.     multi = 0;        /* moves consumed */
  294.     nomovemsg = (char *)0;    /* occupation end message */
  295.  
  296.     buf[0] = (char)0;
  297.     ebuf[0] = (char)0;
  298.     post_engr_text = (char *)0;
  299.     maxelen = BUFSZ - 1;
  300.  
  301.     /* Can the adventurer engrave at all? */
  302.  
  303.     if(u.uswallow) {
  304.         if (is_animal(u.ustuck->data)) {
  305.             pline("What would you write?  \"Jonah was here\"?");
  306.             return(0);
  307.         } else if (is_whirly(u.ustuck->data)) {
  308.             You("can't reach the ground.");
  309.             return(0);
  310.         } else 
  311.             jello = TRUE;
  312.         } else if (is_lava(u.ux, u.uy)) {
  313.         You("can't write on the lava!");
  314.         return(0);
  315.     } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
  316.         You("can't write on the water!");
  317.         return(0);
  318.     }
  319.     if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
  320.         You("can't write in thin air!");
  321.         return(0);
  322.     }
  323. #ifdef POLYSELF
  324.     if (cantwield(uasmon)) {
  325.         You("can't even hold anything!");
  326.         return(0);
  327.     }
  328. #endif
  329.     if (check_capacity(NULL)) return (0);
  330.  
  331.     /* One may write with finger, or weapon, or wand, or..., or...
  332.      * Edited by GAN 10/20/86 so as not to change weapon wielded.
  333.      */
  334.  
  335.     otmp = getobj(styluses, "write with");
  336.     if(!otmp) return(0);        /* otmp == zeroobj if fingers */
  337.  
  338.     /* There's no reason you should be able to write with a wand
  339.      * while both your hands are tied up.
  340.      */
  341.     if (!freehand() && otmp != uwep && !otmp->owornmask) {
  342.         You("have no free %s to write with!", body_part(HAND));
  343.         return(0);
  344.     }
  345.  
  346.     if (jello) {
  347.         You("tickle %s with your %s.", mon_nam(u.ustuck), 
  348.             (otmp == &zeroobj) ? makeplural(body_part(FINGER)) :
  349.             xname(otmp));
  350.         Your("message dissolves...");
  351.         return(0);
  352.     }
  353.     if(Levitation && otmp->oclass != WAND_CLASS){        /* riv05!a3 */
  354.         You("can't reach the floor!");
  355.         return(0);
  356.     }
  357.  
  358.     /* SPFX for items */
  359.  
  360.     switch (otmp->oclass) {
  361.         default:
  362.         case AMULET_CLASS:
  363.         case CHAIN_CLASS:
  364.         case POTION_CLASS:
  365.         case GOLD_CLASS:
  366.         break;
  367.  
  368.         case RING_CLASS:
  369.         /* "diamond" rings and others should work */
  370.         {
  371.             register int i, j;
  372.  
  373.             for (i=0, j=strlen(hard_ring_names[i]); j; i++)
  374.             if ( !strncmp(hard_ring_names[i],
  375.                  OBJ_DESCR(objects[otmp->otyp]),
  376.                  j=strlen(hard_ring_names[i])) ) {
  377.                 type = ENGRAVE;
  378.                 break;
  379.             }
  380.         }
  381.         break;
  382.  
  383.         case GEM_CLASS:
  384.         /* diamonds & other gems should work */
  385.         {
  386.             register int i;
  387.  
  388.             for (i=0; hard_gems[i]; i++)
  389.             if (otmp->otyp == hard_gems[i]) {
  390.                 type = ENGRAVE;
  391.                 break;
  392.             }
  393.         }
  394.         break;
  395.  
  396.         /* Objects too large to engrave with */
  397.         case BALL_CLASS:
  398.         case ROCK_CLASS:
  399.         case ARMOR_CLASS:
  400.         You("can't engrave with such a large object!");
  401.         ptext = FALSE;
  402.         break;
  403.  
  404.         /* Objects too silly to engrave with */
  405.         case FOOD_CLASS:
  406.         case SCROLL_CLASS:
  407.         case SPBOOK_CLASS:
  408.         Your("%s would get too dirty.", xname(otmp));
  409.         ptext = FALSE;
  410.         break;
  411.  
  412.         case RANDOM_CLASS:    /* This should mean fingers */
  413.         break;
  414.  
  415.         /* The charge is removed from the wand before prompting for
  416.          * the engraving text, because all kinds of setup decisions
  417.          * and pre-engraving messages are based upon knowing what type
  418.          * of engraving the wand is going to do.  Also, the player
  419.          * will have potentially seen "You wrest .." message, and
  420.          * therefore will know they are using a charge.
  421.          */
  422.         case WAND_CLASS:
  423.         if (zappable(otmp)) {
  424.             zapwand = TRUE;
  425.             if (Levitation) ptext = FALSE;
  426.  
  427.             switch (otmp->otyp) {
  428.             /* DUST wands */
  429.             default:
  430.             break;
  431.  
  432.             /* NODIR wands */
  433.             case WAN_LIGHT:
  434.             case WAN_SECRET_DOOR_DETECTION:
  435.             case WAN_CREATE_MONSTER:
  436.             case WAN_WISHING:
  437.               zapnodir(otmp);
  438.             break;
  439.  
  440.             /* IMMEDIATE wands */
  441.                 /* If wand is "IMMEDIATE", remember to effect the
  442.              * previous engraving even if turning to dust.,
  443.              */
  444.             case WAN_STRIKING:
  445.             post_engr_text =
  446.             "The wand unsuccessfully fights your attempt to write!";
  447.             break;
  448.             case WAN_SLOW_MONSTER:
  449.             if (!Blind)
  450.                post_engr_text = "The bugs on the ground slow down!";
  451.             break;
  452.             case WAN_SPEED_MONSTER:
  453.             if (!Blind)
  454.                post_engr_text = "The bugs on the ground speed up!";
  455.             break;
  456.             case WAN_POLYMORPH:
  457.             if(oep)  {
  458.                 if (!Blind) {
  459.                 type = (xchar)0;    /* random */
  460.                 Strcpy(buf,random_engraving());
  461.                 }
  462.                 dengr = TRUE;
  463.             }
  464.             break;
  465.             case WAN_NOTHING:
  466.             case WAN_UNDEAD_TURNING:
  467.             case WAN_OPENING:
  468.             case WAN_LOCKING:
  469.             case WAN_PROBING:
  470.             break;
  471.  
  472.             /* RAY wands */
  473.             case WAN_MAGIC_MISSILE:
  474.             ptext = TRUE;
  475.             if (!Blind)
  476.                 post_engr_text =
  477.                 "The ground is riddled by bullet holes!";
  478.             break;
  479.  
  480.             /* can't tell sleep from death - Eric Backus */
  481.             case WAN_SLEEP:
  482.             case WAN_DEATH:
  483.             if (!Blind)
  484.                 post_engr_text =
  485.                 "The bugs on the ground stop moving!";
  486.             break;
  487.  
  488.             case WAN_COLD:
  489.             if (!Blind)
  490.                 post_engr_text =
  491.                 "A few ice cubes drop from the wand.";
  492.             if(!oep || (oep->engr_type != BURN))
  493.                 break;
  494.             case WAN_CANCELLATION:
  495.             case WAN_MAKE_INVISIBLE:
  496.             if(oep) {
  497.                 if (!Blind)
  498.                 pline("The engraving on the floor vanishes!");
  499.                 dengr = TRUE;
  500.             }
  501.             break;
  502.             case WAN_TELEPORTATION:
  503.             if (oep) {
  504.                 if (!Blind)
  505.                 pline("The engraving on the floor vanishes!");
  506.                 teleengr = TRUE;
  507.             }
  508.             break;
  509.  
  510.             /* type = ENGRAVE wands */
  511.             case WAN_DIGGING:
  512.             ptext = TRUE;
  513.             type  = ENGRAVE;
  514.             if(!objects[otmp->otyp].oc_name_known) {
  515.                     if (flags.verbose)
  516.                 pline("This %s is a wand of digging!",
  517.                 xname(otmp));
  518.                 doknown = TRUE;
  519.             }
  520.             if (!Blind)
  521.                 post_engr_text = "Gravel flies up from the floor.";
  522.             else
  523.                 post_engr_text = "You hear drilling!";
  524.             break;
  525.  
  526.             /* type = BURN wands */
  527.             case WAN_FIRE:
  528.             ptext = TRUE;
  529.             type  = BURN;
  530.             if(!objects[otmp->otyp].oc_name_known) {
  531.                 if (flags.verbose)
  532.                 pline("This %s is a wand of fire!", xname(otmp));
  533.                 doknown = TRUE;
  534.             }
  535.             if (!Blind)
  536.                 post_engr_text = "Flames fly from the wand.";
  537.             else
  538.                 post_engr_text = "You feel the wand heat up.";
  539.             break;
  540.             case WAN_LIGHTNING:
  541.             ptext = TRUE;
  542.             type  = BURN;
  543.             if(!objects[otmp->otyp].oc_name_known) {
  544.                     if (flags.verbose)
  545.                 pline("This %s is a wand of lightning!",
  546.                     xname(otmp));
  547.                 doknown = TRUE;
  548.             }
  549.             if (!Blind) {
  550.                 post_engr_text = "Lightning arcs from the wand.";
  551.                 doblind = TRUE;
  552.             } else
  553.                 post_engr_text = "You hear crackling!";
  554.             break;
  555.  
  556.             /* type = MARK wands */
  557.             /* type = BLOOD wands */
  558.             }
  559.         } else /* end if zappable */
  560.             if (Levitation) {
  561.             You("can't reach the floor!");
  562.             return(0);
  563.             }
  564.         break;
  565.  
  566.         case WEAPON_CLASS:
  567.         if(is_blade(otmp))
  568.             if ((int)otmp->spe > -3)
  569.             type = ENGRAVE;
  570.             else
  571.             Your("%s too dull for engraving.", aobjnam(otmp,"are"));
  572.         break;
  573.  
  574.         case TOOL_CLASS:
  575.         if(otmp == ublindf) {
  576.             pline(
  577.         "That is a bit difficult to engrave with, don't you think?");
  578.             return(0);
  579.         }
  580.         switch (otmp->otyp)  {
  581.             case MAGIC_MARKER:
  582.             if (otmp->spe <= 0)
  583.                 Your("marker has dried out.");
  584.             else
  585.                 type = MARK;
  586.             break;
  587.             case TOWEL:
  588.              /* Can't really engrave with a towel */
  589.             ptext = FALSE;
  590.             if (oep)
  591.                 if ((oep->engr_type == DUST ) ||
  592.                 (oep->engr_type == BLOOD) ||
  593.                 (oep->engr_type == MARK )) {
  594.                 if (!Blind)
  595.                     You("wipe out the message here.");
  596.                 else
  597.                     Your("%s gets dusty.", xname(otmp));
  598.                 dengr = TRUE;
  599.                 } else
  600.                 Your("%s can't wipe out this engraving.",
  601.                      xname(otmp));
  602.             else
  603.                 Your("%s gets dusty.", xname(otmp));
  604.             break;
  605.             default:
  606.             break;
  607.         }
  608.         break;
  609.  
  610.         case VENOM_CLASS:
  611. #ifdef WIZARD
  612.         if (wizard) {
  613.             pline("Writing a poison pen letter??");
  614.             break;
  615.         }
  616. #endif
  617.         case ILLOBJ_CLASS:
  618.         impossible("You're engraving with an illegal object!");
  619.         break;
  620.     }
  621.  
  622.     /* End of implement setup */
  623.  
  624.     /* Identify stylus */
  625.     if (doknown) {
  626.         makeknown(otmp->otyp);
  627.         more_experienced(0,10);
  628.     }
  629.  
  630.     if (teleengr) {
  631.         register int tx,ty;
  632.  
  633.         do  {
  634.          tx = rn1(COLNO-3,2);
  635.         ty = rn2(ROWNO);
  636.         } while(!goodpos(tx,ty, (struct monst *)0, (struct permonst *)0));
  637.  
  638.         oep->engr_x = tx;
  639.         oep->engr_y = ty;
  640.  
  641.         oep = (struct engr *)0;
  642.     }
  643.  
  644.     if (dengr) {
  645.         del_engr (oep);
  646.         oep = (struct engr *)0;
  647.     }
  648.  
  649.     /* Something has changed the engraving here */
  650.     if (*buf) {
  651.         make_engr_at(u.ux, u.uy, buf, moves, type);
  652.         pline("The engraving now reads: \"%s\".", buf);
  653.         ptext = FALSE;
  654.     }
  655.  
  656.     if (zapwand && (otmp->spe < 0)) {
  657.         pline("%s %sturns to dust.",
  658.           The(xname(otmp)), Blind ? "" : "glows violently, then ");
  659. You("are not going to get anywhere trying to write in the dust with your dust.");
  660.         useup(otmp);
  661.         ptext = FALSE;
  662.     }
  663.  
  664.     if (!ptext) {        /* Early exit for some implements. */
  665.         if (Levitation && (otmp->oclass == WAND_CLASS))
  666.         You("can't reach the floor!");
  667.         return(1);
  668.     }
  669.  
  670.     /* Special effects should have deleted the current engraving (if
  671.      * possible) by now.
  672.      */
  673.  
  674.     if (oep) {
  675.         register char c = 'n';
  676.  
  677.         /* Give player the choice to add to engraving. */
  678.  
  679.         if ( (type == oep->engr_type) && (!Blind ||
  680.          (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) {
  681.             c = yn_function("Do you want to add to the current engraving?",
  682.                 ynqchars, 'y');
  683.         if (c == 'q') {
  684.             pline("Never mind.");
  685.             return(0);
  686.         }
  687.         }
  688.  
  689.         if (c == 'n' || Blind)
  690.  
  691.         if( (oep->engr_type == DUST) || (oep->engr_type == BLOOD) ||
  692.             (oep->engr_type == MARK) ) {
  693.             if (!Blind) {
  694.             You("wipe out the message that was %s here.",
  695.                 ((oep->engr_type == DUST)  ? "written in the dust" :
  696.                 ((oep->engr_type == BLOOD) ? "scrawled in blood"   :
  697.                              "written")));
  698.             del_engr(oep);
  699.             oep = (struct engr *)0;
  700.             } else
  701.            /* Don't delete engr until after we *know* we're engraving */
  702.             eow = TRUE;
  703.         } else
  704.             if ( (type == DUST) || (type == MARK) || (type == BLOOD) ) {
  705.             You(
  706.                "cannot wipe out the message that is %s the floor here.",
  707.                     (oep->engr_type == BURN) ? "burned into" :
  708.                 "engraved in");
  709.             return(1);
  710.             } else
  711.             if ( (type != oep->engr_type) || (c == 'n') ) {
  712.                 if (!Blind || !Levitation)
  713.                 You("will overwrite the current message.");
  714.                 eow = TRUE;
  715.             }
  716.     }
  717.  
  718.     switch(type){
  719.         default:
  720.         everb = (oep && !eow ? "add to the weird writing on" :
  721.                        "write strangely on");
  722.         eloc  = "the floor";
  723.         break;
  724.         case DUST:
  725.         everb = (oep && !eow ? "add to the writing in" :
  726.                        "write in");
  727.         eloc = "the dust";
  728.         break;
  729.         case ENGRAVE:
  730.         everb = (oep && !eow ? "add to the engraving in" :
  731.                        "engrave in");
  732.         eloc = "the floor";
  733.         break;
  734.         case BURN:
  735.         everb = (oep && !eow ? "add to the text burned into" :
  736.                        "burn into");
  737.         eloc = "the floor";
  738.         break;
  739.         case MARK:
  740.         everb = (oep && !eow ? "add to the graffiti on" :
  741.                        "scribble on");
  742.         eloc = "the floor";
  743.         break;
  744.         case BLOOD:
  745.         everb = (oep && !eow ? "add to the scrawl on" :
  746.                        "scrawl on");
  747.         eloc = "the floor";
  748.         break;
  749.     }
  750.  
  751.     /* Tell adventurer what is going on */
  752.     if (otmp != &zeroobj)
  753.         You("%s %s with %s.", everb, eloc, doname(otmp));
  754.     else
  755.         You("%s %s with your %s.", everb, eloc,
  756.         makeplural(body_part(FINGER)));
  757.  
  758.     /* Prompt for engraving! */
  759.     Sprintf(qbuf,"What do you want to %s %s here?", everb, eloc);
  760.     getlin(qbuf, ebuf);
  761.     clear_nhwindow(WIN_MESSAGE);
  762.  
  763.     /* Mix up engraving if surface or state of mind is unsound.  */
  764.     /* Original kludge by stewr 870708.  modified by njm 910722. */
  765.     for (sp = ebuf; *sp; sp++)
  766.         if ( ((type == DUST || type == BLOOD) && !rn2(25)) ||
  767.          (Blind   && !rn2(9)) || (Confusion     && !rn2(12)) ||
  768.          (Stunned && !rn2(4)) || (Hallucination && !rn2(1)) )
  769.          *sp = '!' + rn2(93); /* ASCII-code only */
  770.  
  771.     /* Count the actual # of chars engraved not including spaces */
  772.     len = strlen(ebuf);
  773.  
  774.     for (sp = ebuf, spct = 0; *sp; sp++) if (isspace(*sp)) spct++;
  775.  
  776.     if ( (len == spct) || index(ebuf, '\033') ) {
  777.         if (zapwand) {
  778.         if (!Blind)
  779.             pline("%s glows, then fades.", The(xname(otmp)));
  780.             return(1);
  781.         } else {
  782.         pline("Never mind.");
  783.         return(0);
  784.         }
  785.     }
  786.  
  787.     len -= spct;
  788.  
  789.     /* Previous engraving is overwritten */
  790.     if (eow) {
  791.         del_engr(oep);
  792.         oep = (struct engr *)0;
  793.     }
  794.  
  795.     /* Figure out how long it took to engrave, and if player has
  796.      * engraved too much.
  797.      */
  798.     switch(type){
  799.         default:
  800.         multi = -(len/10);
  801.         if (multi) nomovemsg = "You finish your weird engraving.";
  802.         break;
  803.         case DUST:
  804.         multi = -(len/10);
  805.         if (multi) nomovemsg = "You finish writing in the dust.";
  806.         break;
  807.         case ENGRAVE:
  808.         multi = -(len/10);
  809.         if ((otmp->oclass == WEAPON_CLASS) &&
  810.             ((otmp->otyp != ATHAME) || otmp->cursed)) {
  811.             multi = -len;
  812.             maxelen = ((otmp->spe + 3) * 2) + 1;
  813.             /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11
  814.              * Note: this does not allow a +0 anything (except
  815.              *     an athame) to engrave "Elbereth" all at once.
  816.              *     However, you could now engrave "Elb", then
  817.              *     "ere", then "th".
  818.              */
  819.             Your("%s dull.", aobjnam(otmp, "get"));
  820.             if (len > maxelen) {
  821.                 multi = -maxelen;
  822.             otmp->spe = -3;
  823.             } else
  824.             if (len > 1) otmp->spe -= len >> 1;
  825.             else otmp->spe -= 1; /* Prevent infinite engraving */
  826.         } else
  827.             if ( (otmp->oclass == RING_CLASS) ||
  828.              (otmp->oclass == GEM_CLASS) )
  829.             multi = -len;
  830.         if (multi) nomovemsg = "You finish engraving.";
  831.         break;
  832.         case BURN:
  833.         multi = -(len/10);
  834.         if (multi)
  835.             nomovemsg =
  836.             "You finish burning your message into the floor.";
  837.         break;
  838.         case MARK:
  839.         multi = -(len/10);
  840.         if ((otmp->oclass == TOOL_CLASS) &&
  841.             (otmp->otyp == MAGIC_MARKER)) {
  842.             maxelen = (otmp->spe) * 2; /* one charge / 2 letters */
  843.             if (len > maxelen) {
  844.             Your("marker dries out.");
  845.             otmp->spe = 0;
  846.             multi = -(maxelen/10);
  847.             } else
  848.             if (len > 1) otmp->spe -= len >> 1;
  849.             else otmp->spe -= 1; /* Prevent infinite grafitti */
  850.         }
  851.         if (multi) nomovemsg = "You finish defacing the dungeon.";
  852.         break;
  853.         case BLOOD:
  854.         multi = -(len/10);
  855.         if (multi) nomovemsg = "You finish scrawling.";
  856.         break;
  857.     }
  858.  
  859.     /* Chop engraving down to size if necessary */
  860.     if (len > maxelen) {
  861.         for (sp = ebuf; (maxelen && *sp); sp++)
  862.         if (!isspace(*sp)) maxelen--;
  863.         if (!maxelen && *sp) {
  864.         *sp = (char)0;
  865.         if (multi) nomovemsg = "You cannot write any more.";
  866.         You("only are able to write \"%s\"", ebuf);
  867.         }
  868.     }
  869.  
  870.     /* Add to existing engraving */
  871.     if (oep) Strcpy(buf, oep->engr_txt);    
  872.  
  873.     (void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
  874.  
  875.     make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
  876.  
  877.     if (post_engr_text) pline(post_engr_text);
  878.  
  879.     if (doblind) {
  880.         You("are blinded by the flash!");
  881.         make_blinded((long)rnd(50),FALSE);
  882.     }
  883.  
  884.     return(1);
  885. }
  886.  
  887. void
  888. save_engravings(fd, mode)
  889. int fd, mode;
  890. {
  891.     register struct engr *ep = head_engr;
  892.     register struct engr *ep2;
  893. #ifdef GCC_WARN
  894.     static long nulls[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  895. #endif
  896.     while(ep) {
  897.         ep2 = ep->nxt_engr;
  898.         if(ep->engr_lth && ep->engr_txt[0]){
  899.         bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
  900.         bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
  901.         }
  902.         if (mode & FREE_SAVE)
  903.         dealloc_engr(ep);
  904.         ep = ep2;
  905.     }
  906.  
  907. #ifdef GCC_WARN
  908.     bwrite(fd, (genericptr_t)nulls, sizeof(unsigned));
  909. #else
  910.     bwrite(fd, (genericptr_t)nul, sizeof(unsigned));
  911. #endif
  912.  
  913.     if (mode & FREE_SAVE)
  914.         head_engr = 0;
  915. }
  916.  
  917. void
  918. rest_engravings(fd) int fd; {
  919. register struct engr *ep;
  920. unsigned lth;
  921.     head_engr = 0;
  922.     while(1) {
  923.         mread(fd, (genericptr_t) <h, sizeof(unsigned));
  924.         if(lth == 0) return;
  925.         ep = newengr(lth);
  926.         mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
  927.         ep->nxt_engr = head_engr;
  928.         head_engr = ep;
  929.         ep->engr_txt = (char *) (ep + 1);    /* Andreas Bormann */
  930.         /* mark as finished for bones levels -- no problem for
  931.          * normal levels as the player must have finished engraving
  932.          * to be able to move again */
  933.         ep->engr_time = moves;
  934.     }
  935. }
  936.  
  937. STATIC_OVL void
  938. del_engr(ep) register struct engr *ep; {
  939. register struct engr *ept;
  940.     if(ep == head_engr)
  941.         head_engr = ep->nxt_engr;
  942.     else {
  943.         for(ept = head_engr; ept; ept = ept->nxt_engr) {
  944.             if(ept->nxt_engr == ep) {
  945.                 ept->nxt_engr = ep->nxt_engr;
  946.                 goto fnd;
  947.             }
  948.         }
  949.         impossible("Error in del_engr?");
  950.         return;
  951.     fnd:    ;
  952.     }
  953.     dealloc_engr(ep);
  954. }
  955.  
  956. #endif /* OVLB */
  957.  
  958. /*engrave.c*/
  959.